#ifndef __M_BINDING_H__
#define __M_BINDING_H__
/**
 * @file binding.hpp
 * @brief 绑定关系管理模块
 * 
 * 本模块实现消息队列绑定关系的声明、删除、持久化存储及内存管理功能。
 * 包含三个核心组件：
 * 1. Binding - 绑定关系数据结构
 * 2. BindingMapper - 数据库持久化管理
 * 3. BindingManager - 内存管理及线程安全操作
 */

#include "../common/logger.hpp"  // 日志系统
#include "../common/helper.hpp"  // 辅助工具（字符串/文件处理）
#include "../common/msg.pb.h"    // Protobuf 消息定义
#include <iostream>
#include <unordered_map>              // 哈希表容器
#include <mutex>                      // 互斥锁
#include <memory>                     // 智能指针

namespace bitmq 
{
    /**
     * @struct Binding
     * @brief 交换机-队列绑定关系数据结构
     * 
     * 表示交换机(exchange)与消息队列(msgqueue)之间的绑定关系，
     * 包含用于消息路由的绑定键(binding_key)。
     */
    struct Binding 
    {
        using ptr = std::shared_ptr<Binding>;  ///< 绑定关系智能指针类型别名
        
        std::string exchange_name;  ///< 交换机名称（最大32字符）
        std::string msgqueue_name;  ///< 消息队列名称（最大32字符）
        std::string binding_key;    ///< 绑定键/路由规则（最大128字符）
        
        Binding() = default;  ///< 默认构造函数
        
        /**
         * @brief 参数化构造函数
         * @param ename 交换机名称
         * @param qname 消息队列名称
         * @param key 绑定键/路由规则
         */
        Binding(const std::string &ename, const std::string &qname, const std::string &key)
            : exchange_name(ename), msgqueue_name(qname), binding_key(key) {}
    };
    
    /// 队列绑定映射类型：队列名称 -> 绑定关系（一个队列在同一交换机下只有一个绑定）
    using MsgQueueBindingMap = std::unordered_map<std::string, Binding::ptr>;
    
    /// 绑定总映射类型：交换机名称 -> 该交换机的所有队列绑定
    using BindingMap = std::unordered_map<std::string, MsgQueueBindingMap>;

    /**
     * @class BindingMapper
     * @brief 绑定关系持久化管理器
     * 
     * 负责绑定关系的数据库存储与恢复操作，使用SQLite作为持久化存储引擎。
     * 提供绑定关系的CRUD（创建、读取、更新、删除）操作接口。
     */
    class BindingMapper 
    {
    public:
        /**
         * @brief 构造函数
         * @param dbfile SQLite数据库文件路径
         * 
         * 执行以下初始化操作：
         * 1. 创建数据库目录（如果不存在）
         * 2. 打开数据库连接
         * 3. 创建绑定关系表
         */
        BindingMapper(const std::string &dbfile)
            : _sql_helper(dbfile) {
            // 确保数据库目录存在
            std::string path = FileHelper::parentDirectory(dbfile);
            FileHelper::createDirectory(path);
            _sql_helper.open();  // 打开数据库连接
            createTable();        // 创建数据表
        }
        
        /**
         * @brief 创建绑定关系存储表
         * 
         * 表结构：
         * - exchange_name: VARCHAR(32)  交换机名
         * - msgqueue_name: VARCHAR(32) 队列名
         * - binding_key: VARCHAR(128)   绑定键
         */
        void createTable()
        {
            std::stringstream sql;
            sql << "CREATE TABLE IF NOT EXISTS binding_table(";
            sql << "exchange_name VARCHAR(32), ";   // 交换机名
            sql << "msgqueue_name VARCHAR(32), ";   // 队列名
            sql << "binding_key VARCHAR(128));";    // 绑定键
            assert(_sql_helper.exec(sql.str(), nullptr, nullptr));
        }
        
        /**
         * @brief 删除绑定关系表（测试用）
         */
        void removeTable() 
        {
            std::string sql = "DROP TABLE IF EXISTS binding_table;";
            _sql_helper.exec(sql, nullptr, nullptr);
        }
        
        /**
         * @brief 插入绑定关系记录
         * @param binding 绑定关系智能指针
         * @return 操作是否成功
         */
        bool insert(Binding::ptr &binding) 
        {
            std::stringstream sql;
            sql << "INSERT INTO binding_table VALUES(";
            sql << "'" << binding->exchange_name << "', ";
            sql << "'" << binding->msgqueue_name << "', ";
            sql << "'" << binding->binding_key << "');";
            return _sql_helper.exec(sql.str(), nullptr, nullptr);
        }
        
        /**
         * @brief 删除指定绑定关系
         * @param ename 交换机名称
         * @param qname 消息队列名称
         */
        void remove(const std::string &ename, const std::string &qname) 
        {
            std::stringstream sql;
            sql << "DELETE FROM binding_table WHERE ";
            sql << "exchange_name='" << ename << "' AND ";
            sql << "msgqueue_name='" << qname << "';";
            _sql_helper.exec(sql.str(), nullptr, nullptr);
        }
        
        /**
         * @brief 删除指定交换机的所有绑定关系
         * @param ename 交换机名称
         * 
         * 通常在删除交换机时调用此方法
         */
        void removeExchangeBindings(const std::string &ename) 
        {
            std::stringstream sql;
            sql << "DELETE FROM binding_table WHERE ";
            sql << "exchange_name='" << ename << "';";
            _sql_helper.exec(sql.str(), nullptr, nullptr);
        }
        
        /**
         * @brief 删除指定消息队列的所有绑定关系
         * @param qname 消息队列名称
         * 
         * 通常在删除消息队列时调用此方法
         */
        void removeMsgQueueBindings(const std::string &qname) 
        {
            std::stringstream sql;
            sql << "DELETE FROM binding_table WHERE ";
            sql << "msgqueue_name='" << qname << "';";
            _sql_helper.exec(sql.str(), nullptr, nullptr);
        }
        
        /**
         * @brief 从数据库恢复所有绑定关系
         * @return 恢复的绑定关系映射
         * 
         * 系统启动时调用此方法加载持久化的绑定关系
         */
        BindingMap recovery() 
        {
            BindingMap result;
            std::string sql = "SELECT exchange_name, msgqueue_name, binding_key FROM binding_table;";
            _sql_helper.exec(sql, selectCallback, &result);  // 回调处理结果集
            return result;
        }
        
    private:
        /**
         * @brief SQL查询回调函数
         * @param arg 用户数据指针（BindingMap类型）
         * @param numcol 返回的列数
         * @param row 行数据数组
         * @param fields 字段名数组
         * @return 操作状态码（0表示成功）
         * 
         * 将数据库查询结果转换为内存中的绑定关系映射
         */
        static int selectCallback(void* arg, int numcol, char** row, char** fields) 
        {
            BindingMap* result = static_cast<BindingMap*>(arg);
            
            // 创建绑定对象（参数顺序：交换机名、队列名、绑定键）
            Binding::ptr bp = std::make_shared<Binding>(row[0], row[1], row[2]);
            
            // 获取或创建该交换机的队列绑定映射
            MsgQueueBindingMap &qmap = (*result)[bp->exchange_name];
            
            // 添加绑定到映射（队列名->绑定关系）
            qmap.emplace(bp->msgqueue_name, bp);
            
            return 0;
        }
        
    private:
        SqliteHelper _sql_helper;  ///< SQLite 数据库操作助手
    };

    /**
     * @class BindingManager
     * @brief 绑定关系管理器
     * 
     * 集成内存管理与持久化操作，提供线程安全的绑定关系管理接口。
     * 负责维护内存中的绑定关系映射，并与数据库保持同步。
     */
    class BindingManager 
    {
    public:
        using ptr = std::shared_ptr<BindingManager>;  ///< 管理器智能指针类型别名
        
        /**
         * @brief 构造函数
         * @param dbfile SQLite数据库文件路径
         * 
         * 初始化时从数据库恢复所有绑定关系到内存
         */
        BindingManager(const std::string &dbfile)
            : _mapper(dbfile) {
            _bindings = _mapper.recovery();  // 加载持久化绑定
        }
        
        /**
         * @brief 创建绑定关系
         * @param ename 交换机名称
         * @param qname 消息队列名称
         * @param key 绑定键/路由规则
         * @param durable 是否持久化存储
         * @return 操作是否成功
         * 
         * 如果绑定关系已存在，直接返回成功（幂等操作）
         */
        bool bind(const std::string &ename, 
                 const std::string &qname, 
                 const std::string &key, 
                 bool durable) {
            std::unique_lock<std::mutex> lock(_mutex);  // 线程安全锁
            
            // 检查绑定是否已存在
            auto eit = _bindings.find(ename);
            if (eit != _bindings.end() && eit->second.find(qname) != eit->second.end()) 
            {
                return true;  // 已存在时直接返回成功
            }
            
            // 创建绑定对象
            Binding::ptr bp = std::make_shared<Binding>(ename, qname, key);
            
            // 持久化处理（根据durable标志决定）
            if (durable) 
            {
                if (!_mapper.insert(bp)) return false;  // 数据库插入失败
            }
            
            // 添加到内存映射
            _bindings[ename].emplace(qname, bp);
            return true;
        }
        
        /**
         * @brief 解除单个绑定关系
         * @param ename 交换机名称
         * @param qname 消息队列名称
         * 
         * 从内存和数据库中同时删除指定的绑定关系
         */
        void unBind(const std::string &ename, const std::string &qname)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto eit = _bindings.find(ename);
            if (eit == _bindings.end()) return;  // 交换机不存在
            
            auto qit = eit->second.find(qname);
            if (qit == eit->second.end()) return;  // 绑定不存在
            
            // 从数据库删除
            _mapper.remove(ename, qname);
            
            // 从内存删除
            eit->second.erase(qname);
        }
        
        /**
         * @brief 删除交换机所有绑定关系
         * @param ename 交换机名称
         * 
         * 通常在删除交换机时调用此方法
         */
        void removeExchangeBindings(const std::string &ename) 
        {
            std::unique_lock<std::mutex> lock(_mutex);
            // 数据库清理
            _mapper.removeExchangeBindings(ename);
            // 内存清理
            _bindings.erase(ename);
        }
        
        /**
         * @brief 删除队列所有绑定关系
         * @param qname 消息队列名称
         * 
         * 通常在删除消息队列时调用此方法
         */
        void removeMsgQueueBindings(const std::string &qname) 
        {
            std::unique_lock<std::mutex> lock(_mutex);
            // 数据库清理
            _mapper.removeMsgQueueBindings(qname);
            
            // 内存清理：遍历所有交换机
            for (auto &exchange : _bindings) 
            {
                // 从每个交换机的绑定映射中删除该队列
                exchange.second.erase(qname);
            }
        }
        
        /**
         * @brief 获取交换机的所有绑定关系
         * @param ename 交换机名称
         * @return 该交换机的绑定关系映射（队列名->绑定关系）
         * 
         * 返回映射的拷贝以保证线程安全
         */
        MsgQueueBindingMap getExchangeBindings(const std::string &ename) 
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto eit = _bindings.find(ename);
            // 返回空映射或实际绑定映射的拷贝（避免外部修改内部数据）
            return (eit != _bindings.end()) ? eit->second : MsgQueueBindingMap{};
        }
        
        /**
         * @brief 获取特定绑定关系
         * @param ename 交换机名称
         * @param qname 消息队列名称
         * @return 绑定关系智能指针（不存在时返回nullptr）
         */
        Binding::ptr getBinding(const std::string &ename, const std::string &qname) 
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto eit = _bindings.find(ename);
            if (eit == _bindings.end()) return nullptr;  // 交换机不存在
            
            auto qit = eit->second.find(qname);
            // 返回绑定指针或空指针
            return (qit != eit->second.end()) ? qit->second : nullptr;
        }
        
        /**
         * @brief 检查绑定关系是否存在
         * @param ename 交换机名称
         * @param qname 消息队列名称
         * @return 是否存在绑定关系
         */
        bool exists(const std::string &ename, const std::string &qname) 
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto eit = _bindings.find(ename);
            if (eit == _bindings.end()) return false;
            return eit->second.find(qname) != eit->second.end();
        }
        
        /**
         * @brief 获取绑定关系总数
         * @return 系统中所有绑定关系的数量
         */
        size_t size() 
        {
            std::unique_lock<std::mutex> lock(_mutex);
            size_t total = 0;
            for (auto &exchange : _bindings) 
            {
                total += exchange.second.size();  // 累加每个交换机的绑定数
            }
            return total;
        }
        
        /**
         * @brief 清空所有绑定关系（测试用）
         * 
         * 警告：仅用于测试环境清理，生产环境慎用！
         * 会删除数据库表并清空内存数据
         */
        void clear() 
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _mapper.removeTable();  // 删除数据库表
            _bindings.clear();      // 清空内存数据
        }
        
    private:
        std::mutex _mutex;      ///< 线程互斥锁（保证操作原子性）
        BindingMapper _mapper;  ///< 持久化管理器
        BindingMap _bindings;   ///< 内存中的绑定关系映射
    };
}

#endif // __M_BINDING_H__